import traceback

import markdown
from django.contrib.auth.hashers import check_password, make_password
from django.shortcuts import render, get_object_or_404, redirect
# Create your views here.
from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_exempt
# rest_framework
from rest_framework import status, mixins
from rest_framework.response import Response
from rest_framework.views import APIView

# settings
from ExtraXueHomepage import settings
from ExtraXueHomepage.settings import LoggerConfig
# models
from Main.models import NoteMenu, NoteArticle, Motto
# serializer
from Main.serializer import MottoSerializer, NoteMenuSerializer, NoteArticleSerializer, ArticleSerializer

# 日志
logger = LoggerConfig().mylogger_basic()
logger.getLogger(__name__)



@cache_page(60, cache='default')
def index(request):
    logger.info("old_正在跳转至homepage首页...")
    data = {
        "page_title": "ExtraXue | HomePage"
    }

    return render(request, 'home.html', context=data)


def home(request):
    logger.info("正在跳转至homepage首页...")
    return redirect('static/dist/homepage/homepage_index.html')


# 获得文章模块内容
class ArticleView(APIView):

    @staticmethod
    def get(request):
        # 展现文章菜单 , 取六个类别
        note_menu_lists = NoteMenu.objects.all().filter(menu_status=1)[0:6]

        note_menu_serializer = NoteMenuSerializer(note_menu_lists, many=True)
        # 文章最近变更的前六篇
        article_lists = NoteArticle.objects.all().order_by("-article_update_time").filter(article_status=True)[0:6]
        note_article_serializer = NoteArticleSerializer(article_lists, many=True)

        return Response({
            "res_status": status.HTTP_200_OK,
            "note_menu_data": note_menu_serializer.data,
            "note_article_data": note_article_serializer.data,
        })

    @staticmethod
    def post(request):
        article_num = request.data["article_num"]
        print(article_num)
        if article_num == "" or article_num is None:
            return Response({
                "res_status": status.HTTP_204_NO_CONTENT,
                "res_msg" : "参数为空！"
            })

        note_article_serializer = {}
        # 获取所有文章
        if article_num.lower() == "all":
            article_lists = NoteArticle.objects.all().order_by("-article_update_time").filter(article_status=True)

            note_article_serializer = NoteArticleSerializer(article_lists, many=True)

        return Response({
            "res_status": status.HTTP_200_OK,
            "article_list": note_article_serializer.data
        })


# 获得文章模块内容
class ArticleCate(APIView):

    @staticmethod
    def get(request):
        # 展现文章类别
        note_cate_lists = NoteMenu.objects.all().filter(menu_status=1)

        note_menu_serializer = NoteMenuSerializer(note_cate_lists, many=True)

        return Response({
            "res_status": status.HTTP_200_OK,
            "note_menu_cate": note_menu_serializer.data,
        })


# 获取某个类别的文章列表
class ArticleCateView(APIView):
    @staticmethod
    def get(request):
        # 取get参数中的category
        category = request.GET.get("category")

        logger.info("当前获取到的文章类别是：%s", category)

        if category is None:
            return Response({
                "res_status": status.HTTP_204_NO_CONTENT,
                "res_msg": "文章类型为空！",
            })

        article_lists = NoteArticle.objects.filter(menu_code__contains=category.lower()).filter(article_status=True)  # 要将menu_code转换成小写

        note_article_serializer = NoteArticleSerializer(article_lists, many=True)

        return Response({
            "res_status": status.HTTP_200_OK,
            "note_article_data": note_article_serializer.data,
        })


# 获取一句格言
class MottoView(APIView):

    @staticmethod
    def get(request):
        # 随机排序
        motto_instance = Motto.objects.order_by("?")

        # 取第一条数据
        serializer = MottoSerializer(instance=motto_instance.first(), many=False)

        return Response({
            "res_code": status.HTTP_200_OK,
            "res_data": serializer.data
        })
        # return Response(serializer.data)


# 获取文章内容
class ArticleContentView(APIView):

    @staticmethod
    def get(request):

        article_id = request.GET.get("articleId")

        if article_id is None or article_id == "":
            return Response({
                "res_status": status.HTTP_204_NO_CONTENT,
                "res_msg": "article id 为空！",
            })

        try:
            article_instance = NoteArticle.objects.filter(pk=article_id).filter(article_status=True)

            if article_instance.exists():

                article_serializer = ArticleSerializer(instance=article_instance.first(), many=False)
                # 正文，markdown语法
                article_content = article_serializer.data['article_content']
                article_name = article_serializer.data['article_name']
                article_author = article_serializer.data['article_author']
                article_create_time = article_serializer.data['article_create_time'][0:10]
                article_update_time = article_serializer.data['article_update_time'][0:10]
                exts = ['markdown.extensions.extra',
                        'markdown.extensions.codehilite',
                        'markdown.extensions.smarty',
                        'markdown.extensions.toc',
                        'markdown.extensions.tables',
                        'markdown.extensions.fenced_code',
                        # 有BUG 无法展现，后面再说吧
                        # 'md_mermaid'
                        ]
                # markdown配置格式：
                # extension_configs = {
                #     'extension_name_1': {
                #         'option_1': 'value_1',
                #         'option_2': 'value_2'
                #     }
                # }
                ext_configs = {
                    "markdown.extensions.codehilite": {
                        # https://python-markdown.github.io/extensions/code_hilite/#syntax
                        # 行数
                        # "linenums": "Yes",
                        "guess_lang": "True",
                    }
                }
                md = markdown.Markdown(extensions=exts, extension_configs=ext_configs)
                article_content = md.convert(article_content)
                article_toc = md.toc

                # markdown2 用法，有bug
                # markdown2 extras wiki : https://github.com/trentm/python-markdown2/wiki/Extras
                # article_content = markdown2.markdown(article_content,
                #                                      extras=['fenced-code-blocks', 'pyshell', 'toc', 'tables',
                #                                              'tag-friendly', 'code-friendly'])
                # article_toc = '<div class = "toc">' + article_content.toc_html + '</div>'
                # mistune使用方法如下：在段落后加入 ..toc:: 即可
                # article_content = mistune.markdown(article_content,plugins=[DirectiveToc()])
                # article_toc = ""
                # 最终选择放弃mistune和markdown2，选择python - markdown
            else:
                return Response({
                    "res_status": status.HTTP_204_NO_CONTENT,
                    "res_msg": "FAILED! 不存在此article id的文章！",
                })
        except Exception as e:

            logger.error(traceback.format_exc())

            return Response({
                "res_status": status.HTTP_500_INTERNAL_SERVER_ERROR,
                "res_msg": "FAILED! The reason is : %s" % repr(e),
            })
        else:
            return Response({
                "res_status": status.HTTP_200_OK,
                "res_msg": "SUCCESS",
                "article_content": article_content,
                "article_name": article_name,
                "article_author": article_author,
                "article_create_time": article_create_time,
                "article_update_time": article_update_time,
                "article_toc": article_toc
            })


# 尝试使用Mixin，有点问题
class MottoViewMixin(mixins.ListModelMixin):
    queryset = Motto.objects.order_by("?")

    serializer_class = MottoSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)


# python markdown直接读取markdown文件的方法
def md2html(filename):
    exts = ['markdown.extensions.extra', 'markdown.extensions.codehilite', 'markdown.extensions.tables',
            'markdown.extensions.toc']
    mdcontent = ""
    with open(filename, 'r', encoding='utf-8') as f:
        mdcontent = f.read()
        pass
    html = markdown.markdown(mdcontent, extensions=exts)
    return html


# old, 已废弃
@csrf_exempt
def mdeditor(request):
    article = get_object_or_404(NoteArticle, pk=1)

    print(article.article_content)

    article.article_content = markdown.markdown(article.article_content,
                                                extensions=[
                                                    'markdown.extensions.extra',
                                                    'markdown.extensions.codehilite',
                                                    'markdown.extensions.toc',
                                                ])

    data = {
        "article": article
    }

    return render(request, 'article.html', context=data)


def article_page(request, articleid):
    article = get_object_or_404(NoteArticle, pk=articleid)

    md = markdown.Markdown(extensions=[
        'markdown.extensions.extra',
        'markdown.extensions.codehilite',
        'markdown.extensions.toc',
    ])

    article.article_content = md.convert(article.article_content)
    # article.article_content = mistune.markdown(article.article_content)
    article.toc = md.toc

    return render(request, 'article.html', context={'article': article, "page_title": article.article_name})


# 验证码机制
class AuthView(APIView):
    def post(self, request):
        try:
            authCode = request.data["authCode"]
            result = check_password(authCode, make_password(settings.AUTH_CODE))
        except Exception as e:
            return Response({
                "res_code": -1,
                "res_msg": "验证错误！原因：{}".format(repr(e))
            })
        return Response({
            "res_code": 0,
            "result": result
        })
